/**
 * NumberFormatter
 *
 * @author Chris Pratt
 *
 * 11/26/2009
 */
package com.anodyzed.onyx.text;

import com.anodyzed.onyx.log.Log;
import com.anodyzed.onyx.log.LogBuilder;
import com.anodyzed.onyx.util.Calc;
import com.anodyzed.onyx.util.FPCalc;
import com.anodyzed.onyx.util.Fraction;
import com.anodyzed.onyx.util.Misc;

import java.text.DecimalFormat;
import java.text.NumberFormat;

public class NumberFormatter extends TextFormatter {
  private static final Log log = LogBuilder.getLogger();
  
  protected NumberFormat fmt;
  protected boolean fraction = false;
  protected boolean duration = false;
  protected TextFormat equation = null;

  /**
   * Constructor
   *  
   * @param parent The parent TextFormat
   * @param key The Argument Index or Map Key for this node 
   * @param bean The additional Bean reference String 
   */
  public NumberFormatter (TextFormat parent,CharSequence key,CharSequence bean) {
    super(parent,key,bean);
    fmt = NumberFormat.getInstance();
  } //NumberFormatter

  /**
   * Constructor
   *  
   * @param parent The parent TextFormat 
   * @param key The Argument Index or Map Key for this node 
   * @param bean The additional Bean reference String 
   * @param style The Numeric Style
   */
  public NumberFormatter (TextFormat parent,CharSequence key,CharSequence bean,CharSequence style) {
    super(parent,key,bean);
    String format = style.toString();
    switch(format) {
      case "currency":
        fmt = NumberFormat.getCurrencyInstance();
        break;
      case "percent":
        fmt = NumberFormat.getPercentInstance();
        break;
      case "integer":
        fmt = NumberFormat.getIntegerInstance();
        break;
      case "fraction":
        fraction = true;
        break;
      case "duration":
        duration = true;
        break;
      default:
        if(format.startsWith("calc,")) {
          equation = parent.subformat(format.substring(5));
        } else if(format.startsWith("integer,")) {
          fmt = NumberFormat.getIntegerInstance();
          equation = parent.subformat(format.substring(8));
        } else if(format.startsWith("duration,")) {
          duration = true;
          equation = parent.subformat(format.substring(9));
        } else {
          fmt = new DecimalFormat(format);
        }
        break;
    }
  } //NumberFormatter

  /**
   * Return a string representation of a numeric object
   *
   * @param args The Formatting Arguments
   * @return The Formatted String
   */
  @Override
  public String toString (Object... args) {
    Object arg = getValue(args);
    if(arg != null) {
      if(fraction) {
        if(arg instanceof Number) {
          return Fraction.toString(((Number)arg).doubleValue());
        } else if(arg instanceof String) {
          return Fraction.toString((String)arg);
        }
      } else if(duration) {
        if(equation != null) {
          return Misc.duration(Calc.eval(equation.format(args)));
        } else if(arg instanceof Number) {
          return Misc.duration(((Number)arg).longValue());
        } else if(arg instanceof String) {
          return Misc.duration(Long.parseLong((String)arg));
        }
      } else if(equation != null) {
        String eq = equation.format(args);
        if(fmt != null) {
          return (eq.indexOf('.') != -1) ? fmt.format(FPCalc.eval(eq)) : fmt.format(Calc.eval(eq));
        } else {
          return (eq.indexOf('.') != -1) ? FPCalc.toString(eq) : Calc.toString(eq);
        }
      } else {
        try {
          return fmt.format(arg);
        } catch(IllegalArgumentException x) {
          log.debug("Unable to format {0} ({0.class.name}) as a Number using ({1})",arg,fmt);
        }
      }
    }
    return null;
  } //toString

} //*NumberFormatter
